import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import prisma from '@/lib/prisma'
import { Prisma } from '@prisma/client'
import type { Experiment, ExperimentStage, TestCase, ExperimentAuthorization } from '@prisma/client'

// 定义类型
type StageWithTestCases = ExperimentStage & {
  content: {
    testCases: TestCase[]
  }
}

type ExperimentWithStages = Experiment & {
  stages: StageWithTestCases[]
  authorizedExperiments: ExperimentAuthorization[]
}

// 获取单个实验详情
export async function GET(
  req: NextRequest,
  { params }: { params: { id: string } }
) {
  try {
    const session = await getServerSession(authOptions)
    if (!session) {
      return NextResponse.json({ message: '未授权，请先登录' }, { status: 401 })
    }

    const { id } = params
    console.log(`获取实验详情，实验ID: ${id}，用户: ${session.user.email}，角色: ${session.user.role}`)

    // 首先检查实验是否存在
    const experiment = await prisma.experiment.findUnique({
      where: { id },
      include: {
        stages: {
          orderBy: {
            order: 'asc',
          },
        },
        resources: true,
        createdBy: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
        authorizedExperiments: {
          include: {
            student: {
              select: {
                id: true,
                name: true,
                email: true,
              },
            },
          },
        },
      },
    })

    if (!experiment) {
      console.log(`实验不存在 ID: ${id}`)
      return NextResponse.json({ message: '实验不存在' }, { status: 404 })
    }

    // 检查用户权限
    const role = session.user.role
    const userId = session.user.id

    // 管理员和教师可以查看所有实验，实验创建者也可以查看
    if (role === 'ADMIN' || role === 'TEACHER' || experiment.createdById === userId) {
      console.log(`用户有管理权限或是创建者，允许访问`)
      return NextResponse.json({ 
        experiment,
        userRole: role 
      })
    }

    console.log(`学生用户尝试访问实验，检查是否有权限`)
    
    // 为学生用户检查实验提交记录
    let submission = null
    
    // 检查该学生是否有这个实验的提交记录
    submission = await prisma.experimentSubmission.findFirst({
      where: {
        experimentId: id,
        studentId: userId,
      },
    })
    
    // 如果已经有提交记录，允许访问
    if (submission) {
      console.log(`学生有实验提交记录，允许访问`)
      return NextResponse.json({
        experiment,
        submission,
        userRole: role
      })
    }

    // 检查学生是否在与该实验关联的小组中
    const userInGroup = await prisma.groupMember.findFirst({
      where: {
        userId,
        group: {
          experimentId: id,
        },
      },
    })

    if (userInGroup) {
      console.log(`学生属于实验相关小组，允许访问`)
      return NextResponse.json({ 
        experiment,
        userRole: role
      })
    }
    
    // 检查学生是否在授权学生列表中
    const isAuthorized = await prisma.experimentAuthorization.findFirst({
      where: {
        experimentId: id,
        studentId: userId,
      },
    })
    
    if (isAuthorized) {
      console.log(`学生在授权列表中，允许访问`)
      
      // 为授权学生创建提交记录（如果没有）
      if (!submission) {
        try {
          submission = await prisma.experimentSubmission.create({
            data: {
              studentId: userId,
              experimentId: id,
              status: 'IN_PROGRESS',
            },
          })
          console.log(`已为授权学生创建提交记录 ID: ${submission.id}`)
        } catch (createError) {
          console.error(`创建提交记录失败:`, createError)
        }
      }
      
      return NextResponse.json({
        experiment,
        submission,
        userRole: role
      })
    }

    // 如果实验已经开始且允许公开访问，则自动创建提交记录并允许访问
    const now = new Date()
    const startTime = new Date(experiment.startTime)
    
    if (now >= startTime && role === 'STUDENT') {
      console.log(`实验已开始，为学生创建提交记录`)
      
      try {
        // 创建新的实验提交记录
        submission = await prisma.experimentSubmission.create({
          data: {
            studentId: userId,
            experimentId: id,
            status: 'IN_PROGRESS',
          },
        })
        
        console.log(`已为学生创建提交记录 ID: ${submission.id}`)
        
        return NextResponse.json({
          experiment,
          submission,
          userRole: role
        })
      } catch (createError) {
        console.error(`创建提交记录失败:`, createError)
        // 即使创建提交记录失败，仍然允许学生访问实验内容
      }
    }

    // 如果以上条件都不满足，则拒绝访问
    console.log(`学生无权访问此实验`)
    return NextResponse.json({ 
      message: '您没有权限访问此实验，请联系教师或管理员' 
    }, { status: 403 })
    
  } catch (error) {
    console.error('获取实验详情失败:', error)
    return NextResponse.json({ 
      message: '获取实验详情失败：' + (error instanceof Error ? error.message : '未知错误') 
    }, { status: 500 })
  }
}

// 更新实验
export async function PUT(
  req: NextRequest,
  { params }: { params: { id: string } }
) {
  try {
    const session = await getServerSession(authOptions)
    if (!session) {
      return NextResponse.json({ message: '未授权' }, { status: 401 })
    }

    const { id: experimentId } = params
    console.log(`开始更新实验，ID: ${experimentId}`)

    // 检查实验是否存在
    const existingExperiment = await prisma.experiment.findUnique({
      where: { id: experimentId },
      include: { 
        stages: true,
        authorizedExperiments: true,
      },
    })

    if (!existingExperiment) {
      console.log(`实验不存在，ID: ${experimentId}`)
      return NextResponse.json({ message: '实验不存在' }, { status: 404 })
    }

    // 检查权限
    if (
      session.user.role !== 'ADMIN' &&
      session.user.role !== 'TEACHER' &&
      existingExperiment.createdById !== session.user.id
    ) {
      console.log(`权限不足，用户: ${session.user.email}, 角色: ${session.user.role}`)
      return NextResponse.json({ message: '权限不足' }, { status: 403 })
    }

    // 解析请求数据
    const data = await req.json()
    console.log('接收到的更新数据:', { ...data, stages: `${data.stages?.length || 0}个阶段` })
    
    const { title, description, content, startTime, endTime, allowLateSubmission, stages, authorizedExperiments } = data

    // 验证输入
    if (!title || !startTime || !endTime) {
      console.log('缺少必要参数')
      return NextResponse.json({ message: '缺少必要参数' }, { status: 400 })
    }

    try {
      // 开始事务处理
      const updatedExperiment = await prisma.$transaction(async (tx) => {
        console.log('开始事务处理')
        
        // 1. 更新实验基本信息
        const experimentBasicInfo = await tx.experiment.update({
          where: { id: experimentId },
          data: {
            title,
            description,
            startTime: new Date(startTime),
            endTime: new Date(endTime),
            allowLateSubmission: allowLateSubmission ?? existingExperiment.allowLateSubmission,
          },
        })
        console.log('实验基本信息已更新', experimentBasicInfo.id)
        
        // 2. 处理实验阶段 (Stages) 和测试用例 (TestCases)
        if (stages && Array.isArray(stages)) {
          console.log(`准备处理 ${stages.length} 个实验阶段`);

          const currentStages = await tx.experimentStage.findMany({
            where: { experimentId: experimentId },
            select: { id: true }
          });
          const currentStageIds = currentStages.map(stage => stage.id);
          const incomingStageClientIds = stages.map((s: any) => s.id).filter(id => id); // 前端传来的、已存在的阶段ID

          // 2a. 删除不再存在的阶段
          const stageIdsToDelete = currentStageIds.filter(id => !incomingStageClientIds.includes(id));
          if (stageIdsToDelete.length > 0) {
            console.log(`将删除 ${stageIdsToDelete.length} 个阶段:`, stageIdsToDelete);
            // 注意：与这些阶段关联的 TestCase 会因为 schema 中的 onDelete: Cascade 而被自动删除
          await tx.experimentStage.deleteMany({
              where: { id: { in: stageIdsToDelete } },
            });
          }

          // 2b. 遍历处理传入的每个阶段 (创建或更新)
          for (const [index, stageData] of stages.entries()) {
            const { id: stageClientId, title: stageTitle, description: stageDescription, type: stageType, content: rawStageContent, order: stageOrder } = stageData;
            
            // Ensure stageContent is an object for CODE stages to handle testCases
            let stageContent = typeof rawStageContent === 'string' ? JSON.parse(rawStageContent) : rawStageContent || {};
            if (typeof stageContent === 'string') {
              try {
                stageContent = JSON.parse(stageContent);
              } catch (e) {
                console.error(`阶段 ${stageData.id || 'new'} 的 content 解析失败:`, stageContent, e);
                stageContent = {}; 
              }
            }
            stageContent = stageContent || {}; // Ensure it's an object

            // --- START: TestCase Handling and Language/Version for CODE stages ---
            if (stageType === 'CODE') {
              console.log(`处理CODE类型阶段: ${stageTitle || stageData.id}`);
              
              // Explicitly set/update language and languageVersion in stageContent
              // These should come from the frontend (stageData.content might already have them, or they might be top-level in stageData)
              // Assuming they are passed within stageData.content for consistency or directly on stageData
              if (stageData.content?.language) { // Check if language is nested in content from frontend
                stageContent.language = stageData.content.language;
              } else if (stageData.language) { // Check if language is a direct property of stageData
                 stageContent.language = stageData.language;
              }
              // else it might be intentionally undefined if not set in UI

              if (stageData.content?.languageVersion) { // Check for languageVersion nested in content
                stageContent.languageVersion = stageData.content.languageVersion;
              } else if (stageData.languageVersion) { // Check for languageVersion as direct property
                stageContent.languageVersion = stageData.languageVersion;
              }
              // else it might be intentionally undefined

              console.log(`阶段 ${stageData.title || stageData.id} 配置的语言: ${stageContent.language}, 版本: ${stageContent.languageVersion}`);

              let processedTestCasesForContent: any[] = []; 

              if (stageContent.testCases && Array.isArray(stageContent.testCases)) {
                const testCasesToProcess = stageContent.testCases;
                const existingTestCaseIdsInStage = (await tx.testCase.findMany({
                    where: { stageId: stageData.id }, // This requires stageData.id to be known for existing stages
                    select: { id: true }
                })).map(tc => tc.id);

                const testCaseIds = (await Promise.all(testCasesToProcess.map(async (tc: any) => {
                  if (tc.id) return tc.id;
                  const newTc = await tx.testCase.create({
                    data: {
                      name: tc.name,
                      input: tc.input,
                      expectedOutput: tc.expectedOutput,
                      points: tc.points || 1.0,
                      stage: {
                        connect: {
                          id: tc.stageId
                        }
                      }
                    },
                  });
                  return newTc.id;
                }))).map((tc: string) => tc);

                const incomingTestCaseIds = testCasesToProcess.map((tc: TestCase) => tc.id).filter(Boolean);

                const testCasesToDelete = existingTestCaseIdsInStage.filter(id => !incomingTestCaseIds.includes(id));
                if (testCasesToDelete.length > 0) {
                    console.log(`从阶段 ${stageData.id} 删除 ${testCasesToDelete.length} 个测试用例:`, testCasesToDelete);
                    await tx.testCase.deleteMany({
                        where: { id: { in: testCasesToDelete } }
                    });
                }
                
                for (const tcData of testCasesToProcess) {
                  const { id: tcId, name, description, input, expectedOutput, points, isHidden, explanation } = tcData;
                  let upsertedTc;
                  // stageData.id needs to be valid for linking test cases, esp for new stages.
                  // If stageData.id is undefined (new stage), it means the stage itself must be created first,
                  // then its ID used for creating test cases. 
                  // The current loop structure implies stageData.id is available.
                  // Let's assume stageData.id is the ID of the stage being processed (either existing or just created if code is restructured)

                  // This part of the logic relies on stageData.id already being the DB ID of the stage.
                  // If it's a new stage, it must be created *before* this loop, or test cases created after the loop.
                  // For simplicity, assuming stageData.id is the correct, persisted stage ID.

                  if (tcId && existingTestCaseIdsInStage.includes(tcId)) { 
                    upsertedTc = await tx.testCase.update({
                      where: { id: tcId },
                      data: { name, description, input, expectedOutput, points: Number(points) || 0, isHidden: Boolean(isHidden), explanation, stageId: stageData.id },
                    });
                  } else { 
                    upsertedTc = await tx.testCase.create({
                      data: { name, description, input, expectedOutput, points: Number(points) || 0, isHidden: Boolean(isHidden), explanation, stageId: stageData.id },
                    });
                  }
                  processedTestCasesForContent.push({ ...tcData, id: upsertedTc.id });
                }
              }
              stageContent.testCases = processedTestCasesForContent;
              console.log(`阶段 ${stageData.title || stageData.id} 更新后的测试用例 (含DB ID):`, stageContent.testCases.map((tc: TestCase) => ({id: tc.id, name: tc.name})));
            }
            // --- END: TestCase Handling and Language/Version ---

            const stagePayload: Prisma.ExperimentStageUncheckedCreateInput | Prisma.ExperimentStageUncheckedUpdateInput = {
              title: stageTitle,
              description: stageDescription || '',
              type: stageType,
              content: JSON.stringify(stageContent), // This now includes language, languageVersion, and testCases with DB IDs
              order: stageOrder !== undefined ? stageOrder : index + 1,
              experimentId: experimentId,
            };

            let currentStageId: string;
            let isNewStage = false;

            if (stageClientId && currentStageIds.includes(stageClientId)) { // 更新现有阶段
              console.log(`更新阶段 ID: ${stageClientId}`);
              const updatedStage = await tx.experimentStage.update({
                where: { id: stageClientId },
                data: stagePayload,
              });
              currentStageId = updatedStage.id;
            } else { // 创建新阶段
              console.log(`创建新阶段: ${stageTitle}`);
              const newStage = await tx.experimentStage.create({
                // experimentId 包含在 stagePayload 中
                data: stagePayload as Prisma.ExperimentStageCreateInput,
              });
              currentStageId = newStage.id;
              isNewStage = true;
            }
          }
        } else {
          // 如果请求中没有 stages 数组，可以选择删除所有现有阶段 (如果业务逻辑如此要求)
          // console.log('请求中未提供阶段信息，将删除所有现有阶段');
          // await tx.experimentStage.deleteMany({ where: { experimentId: experimentId } });
        }

        // 3. 处理授权学生 (authorizedExperiments)
        if (authorizedExperiments && Array.isArray(authorizedExperiments)) {
          const studentIdsToAuthorize = authorizedExperiments; // 前端传来的是 studentId 数组
          console.log(`准备处理 ${studentIdsToAuthorize.length} 个授权学生`);

          // 获取当前实验的所有授权记录
          const currentAuthorizations = await tx.experimentAuthorization.findMany({
            where: { experimentId: experimentId },
            select: { studentId: true }
          });
          const currentAuthorizedStudentIds = currentAuthorizations.map(auth => auth.studentId);

          // 找出需要删除的授权 (在当前授权中，但不在新列表中)
          const authorizationsToDelete = currentAuthorizedStudentIds.filter(
            studentId => !studentIdsToAuthorize.includes(studentId)
          );
          if (authorizationsToDelete.length > 0) {
            console.log(`将删除 ${authorizationsToDelete.length} 个学生的授权:`, authorizationsToDelete);
          await tx.experimentAuthorization.deleteMany({
              where: {
                experimentId: experimentId,
                studentId: { in: authorizationsToDelete }
              }
            });
          }

          // 找出需要新增的授权 (在新列表中，但不在当前授权中)
          const authorizationsToCreate = studentIdsToAuthorize.filter(
            studentId => !currentAuthorizedStudentIds.includes(studentId)
          );
          if (authorizationsToCreate.length > 0) {
            console.log(`将为 ${authorizationsToCreate.length} 个学生创建授权:`, authorizationsToCreate);
              await tx.experimentAuthorization.createMany({
              data: authorizationsToCreate.map((studentId: string) => ({
                experimentId: experimentId,
                studentId: studentId,
              })),
            });
          }
        } else if (authorizedExperiments === null || (Array.isArray(authorizedExperiments) && authorizedExperiments.length === 0)) {
          // 如果 authorizedExperiments 是 null 或空数组，则删除所有现有授权
          console.log('请求中授权学生列表为空或null，将删除所有现有授权');
          await tx.experimentAuthorization.deleteMany({
            where: { experimentId: experimentId },
          });
        }
        // 如果 authorizedExperiments 是 undefined，则不修改现有授权

        console.log('查询事务完成后最终的实验详情');
        return tx.experiment.findUnique({
          where: { id: experimentId },
          include: {
            stages: {
              orderBy: { order: 'asc' },
              include: { testCases: { orderBy: { createdAt: 'asc' } } }, // 返回时包含测试用例
            },
            authorizedExperiments: {
              include: {
                student: { select: { id: true, name: true, email: true } },
              },
            },
            createdBy: { select: { id: true, name: true, email: true } },
            resources: true,
          },
        });
      }); // 事务结束

      console.log('实验更新成功，返回数据');
      return NextResponse.json({ experiment: updatedExperiment });
    } catch (txError) {
      console.error('事务处理失败:', txError)
      if (txError instanceof Prisma.PrismaClientKnownRequestError && txError.code === 'P2003') {
        return NextResponse.json({ message: '更新失败：操作违反了数据关联约束。' , details: txError.message }, { status: 409 });
      }
      return NextResponse.json({ 
        message: '更新实验失败: ' + (txError instanceof Error ? txError.message : '未知事务错误')
      }, { status: 500 })
    }
  } catch (error) {
    console.error('更新实验失败:', error)
    return NextResponse.json({ 
      message: '服务器错误: ' + (error instanceof Error ? error.message : '未知错误')
    }, { status: 500 })
  }
}

// 删除实验
export async function DELETE(
  req: NextRequest,
  { params }: { params: { id: string } }
) {
  try {
    const session = await getServerSession(authOptions)
    if (!session) {
      return NextResponse.json({ message: '未授权' }, { status: 401 })
    }

    const { id: experimentId } = params;

    const experiment = await prisma.experiment.findUnique({
      where: { id: experimentId },
    })

    if (!experiment) {
      return NextResponse.json({ message: '实验不存在' }, { status: 404 })
    }

    if (
      session.user.role !== 'ADMIN' &&
      experiment.createdById !== session.user.id
    ) {
      return NextResponse.json({ message: '权限不足' }, { status: 403 })
    }

    await prisma.$transaction(async (tx) => {
      // 1. 获取所有与该实验相关的 ExperimentStage IDs
      const stagesToDelete = await tx.experimentStage.findMany({
        where: { experimentId: experimentId },
        select: { id: true },
      });
      const stageIds = stagesToDelete.map(s => s.id);

      // 2. 删除所有引用这些 ExperimentStage IDs 的 StageSubmission 记录
      if (stageIds.length > 0) {
        await tx.stageSubmission.deleteMany({
          where: { stageId: { in: stageIds } },
        });
      }
      
      // 3. 删除 Submission 记录 (正式提交快照) - 这些也可能间接与 ExperimentStage 有关
      // (虽然 StageSubmission 已删除，但保持此步骤以确保数据清理的完整性)
      await tx.submission.deleteMany({
        where: { experimentId: experimentId },
      });

      // 4. 删除 ExperimentSubmission 记录 (草稿)
      await tx.experimentSubmission.deleteMany({
        where: { experimentId: experimentId },
      });

      // 5. 删除其他直接关联到 Experiment 的记录
      await tx.resource.deleteMany({
        where: { experimentId: experimentId },
      });
      await tx.group.deleteMany({
        where: { experimentId: experimentId },
      });
      await tx.announcement.deleteMany({
        where: { experimentId: experimentId },
      });
      await tx.forumQuestion.deleteMany({
        where: { experimentId: experimentId },
      });

      // 6. 现在可以安全删除 ExperimentStage 了 (因为相关的 StageSubmissions 已被删除)
      if (stageIds.length > 0) { // Only delete if there were stages
        await tx.experimentStage.deleteMany({
          where: { id: { in: stageIds } }, // More specific delete
        });
      }

      // 7. 最后删除 Experiment 本身
      await tx.experiment.delete({
        where: { id: experimentId },
      });
    });

    return NextResponse.json({ message: '实验已成功删除' });
  } catch (error) {
    console.error('删除实验失败:', error);
    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2003') {
        return NextResponse.json({ message: '删除实验失败：存在无法自动处理的关联数据。' , details: error.message }, { status: 409 });
    }
    return NextResponse.json({ message: '服务器错误，删除实验失败' }, { status: 500 });
  }
} 